package gui;

import gui.chatarea.OpenTabListener;
import gui.dialog.ChatUsernameDialog;
import gui.userslist.UserSelectListener;

import java.awt.Dimension;
import java.awt.Event;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

import ui.StateObserver;
import user.LocalUser;
import user.User;
import utils.IconManager;
import utils.IconManager.IconType;

import network.SendSignalException;

import controller.MessageController;
import controller.UserNotConnected;

public class ChatMenuBar extends JMenuBar implements ActionListener, StateObserver, UserSelectListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private Window master ;
	/* Information dialog... */
	private JDialog aproposDialog ;
	private JDialog connectDialog ;
	private JDialog dialogLogin ;
	private JDialog networkConfigDialog ;
	/* All the items from menu / submenu */
	private JMenuItem connectItem ;
	private JMenuItem changeLoginItem ;
	private JMenuItem disconnectItem ;
	private JMenuItem quitItem ;
	private JMenuItem openTabItem ;
	private JMenuItem closeTabItem ;
	private JMenuItem sendFileItem ;
	private JMenuItem networkConfigItem ;
	private JMenuItem aproposItem ;
	
	/**
	 * Item that should be displayed only if online / offline
	 */
	private JMenuItem[] onlineItems ;
	private JMenuItem[] offlineItems ;
	
	/* The action to perform when send file is clicked. */
	private AbstractAction sendFileAction = null ; 
	
	private MessageController messageController ;
	private OpenTabListener openTabListener ;
	
	/**
	 * Create and return the main menu.
	 * 
	 * @return
	 */
	private JMenu createMainMenu () {
		JMenu mainMenu = new JMenu("Connexion") ;
		mainMenu.setMnemonic(KeyEvent.VK_F) ;
		this.connectItem = new JMenuItem("Connexion", new ImageIcon(IconManager.getIcon(IconType.CONNECT))) ;
		this.connectItem.addActionListener(this) ;
		this.connectItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK)) ;
		this.changeLoginItem = new JMenuItem("Changer de login", new ImageIcon(IconManager.getIcon(IconType.CHANGE_LOGIN))) ;
		this.changeLoginItem.addActionListener(this) ;
		this.changeLoginItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Event.CTRL_MASK)) ;
		this.disconnectItem = new JMenuItem("Deconnexion", new ImageIcon(IconManager.getIcon(IconType.DISCONNECT))) ;
		this.disconnectItem.addActionListener(this) ;
		this.disconnectItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Event.CTRL_MASK)) ;
		this.quitItem = new JMenuItem("Quitter", new ImageIcon(IconManager.getIcon(IconType.QUIT))) ;
		this.quitItem.addActionListener(this) ;
		this.quitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Event.CTRL_MASK)) ;
		mainMenu.add(this.connectItem) ;
		mainMenu.add(this.changeLoginItem) ;
		mainMenu.add(this.disconnectItem) ;
		mainMenu.addSeparator() ;
		mainMenu.add(this.quitItem) ;
		return mainMenu ;
	}
	
	/**
	 * Create and return the room menu
	 * 
	 * @return
	 */
	private JMenu createTabMenu () {
		JMenu mainMenu = new JMenu("Salons") ;
		mainMenu.setMnemonic(KeyEvent.VK_S) ;
		this.openTabItem = new JMenuItem("Salon principal", new ImageIcon(IconManager.getIcon(IconType.DIALOG))) ;
		this.openTabItem.addActionListener(this) ;
		this.openTabItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, Event.CTRL_MASK)) ;
		this.closeTabItem = new JMenuItem("Fermer le salon", new ImageIcon(IconManager.getIcon(IconType.MENU_CLOSE_TAB))) ;
		this.closeTabItem.addActionListener(this) ;
		this.closeTabItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK)) ;
		mainMenu.add(this.openTabItem) ;
		mainMenu.addSeparator() ;
		mainMenu.add(this.closeTabItem) ;
		return mainMenu ;
	}
	
	/**
	 * Create and return the file menu
	 * 
	 * @return
	 */
	private JMenu createFileMenu () {
		JMenu fileMenu = new JMenu("Fichier") ;
		fileMenu.setMnemonic(KeyEvent.VK_F) ;
		this.sendFileItem = new JMenuItem("Envoyer un fichier", new ImageIcon(IconManager.getIcon(IconType.FILE))) ;
		this.sendFileItem.addActionListener(this) ;
		this.sendFileItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK)) ;
		fileMenu.add(this.sendFileItem) ;
		return fileMenu ;
	}
	
	/**
	 * Create and return the config menu.
	 * 
	 * @return
	 */
	private JMenu createConfigMenu () {
		JMenu configMenu = new JMenu("Paramètre(s)") ;
		configMenu.setMnemonic(KeyEvent.VK_P) ;
		this.networkConfigItem = new JMenuItem("Configuration réseau", new ImageIcon(IconManager.getIcon(IconType.CONFIG))) ;
		this.networkConfigItem.addActionListener(this) ;
		this.networkConfigItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, Event.CTRL_MASK)) ;
		configMenu.add(this.networkConfigItem) ;
		return configMenu ;
	}
	
	/**
	 * Create and return the apropos menu.
	 * 
	 * @return
	 */
	private JMenu createAproposMenu () {
		JMenu aproposMenu = new JMenu("À propos") ;
		this.aproposItem = new JMenuItem("À propos", new ImageIcon(IconManager.getIcon(IconType.APROPOS))) ;
		this.aproposItem.addActionListener(this) ;
		aproposMenu.add(this.aproposItem) ;
		return aproposMenu ;
	}
	
	public ChatMenuBar (Window master, 
			JDialog connectDialog, 
			JDialog aproposDialog, 
			JDialog networkConfigDialog, 
			OpenTabListener otl, 
			MessageController mo) {
		super () ;
		this.master = master ;
		this.messageController = mo ;
		this.connectDialog = connectDialog ;
		this.dialogLogin = new ChatUsernameDialog(master, mo) ;
		this.aproposDialog = aproposDialog ;
		this.networkConfigDialog = networkConfigDialog ;
		this.openTabListener = otl ;
		/* Create and add menu... */
		add(createMainMenu()) ;
		add(createTabMenu()) ;
		add(createFileMenu()) ;
		add(createConfigMenu()) ;
		add(createAproposMenu()) ;
		setMaximumSize(new Dimension(Short.MAX_VALUE, 25)) ;
		setMinimumSize(new Dimension(0, 25)) ;
		setSize(new Dimension(0, 25)) ;
		/* Put item into array... */
		this.onlineItems = new JMenuItem[] {
			this.connectItem,
			this.changeLoginItem,
			this.sendFileItem
		} ;
		this.offlineItems = new JMenuItem[] {
			this.connectItem,
			this.networkConfigItem
		} ;
		this.fireDisconnect() ;
		this.userSelected(null) ;
	}

	@Override
	public void fireConnect() {
		for (JMenuItem online : this.onlineItems) {
			online.setEnabled(true) ;
		}
		for (JMenuItem offline : this.offlineItems) {
			offline.setEnabled(false) ;
		}
	}

	@Override
	public void fireDisconnect() {
		for (JMenuItem online : this.onlineItems) {
			online.setEnabled(false) ;
		}
		for (JMenuItem offline : this.offlineItems) {
			offline.setEnabled(true) ;
		}
	}
	

	@Override
	public void userSelected(Set<User> users) {
			
		if (users == null || users.isEmpty()) {
			this.sendFileAction = new AbstractAction() {	
				/**
				 * 
				 */
				private static final long serialVersionUID = 1L;
				@Override
				public void actionPerformed(ActionEvent arg0) {
					JOptionPane.showMessageDialog(ChatMenuBar.this.getParent(), 
							"Vous devez selectionner une personne avant de pouvoir envoyer un fichier." , 
							"Envoi impossible", JOptionPane.WARNING_MESSAGE) ;
				}
			} ;		
		}
		else if (users.size() > 1) {
			this.sendFileAction = new AbstractAction() {	
				/**
				 * 
				 */
				private static final long serialVersionUID = 1L;
				@Override
				public void actionPerformed(ActionEvent arg0) {
					JOptionPane.showMessageDialog(ChatMenuBar.this.getParent(), 
							"Vous ne pouvez envoyer un fichier qu'à une seule personne." , 
							"Envoi impossible", JOptionPane.WARNING_MESSAGE) ;
				}
			} ;	
		}
		else {
			User u = users.iterator().next() ;
			if (u == null || u.equals(LocalUser.getLocalUser())) {
				this.sendFileAction = new AbstractAction() {	
					/**
					 * 
					 */
					private static final long serialVersionUID = 1L;
					@Override
					public void actionPerformed(ActionEvent arg0) {
						JOptionPane.showMessageDialog(ChatMenuBar.this.getParent(), 
								"Vous ne pouvez envoyer un fichier à vous même." , 
								"Envoi impossible", JOptionPane.WARNING_MESSAGE) ;
					}
				} ;	
			}
			else {
				this.sendFileAction = new SendFileAction(getParent(), this.messageController, u) ;
			}
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == this.disconnectItem && this.messageController.connected()) {
			if (JOptionPane.showConfirmDialog(this.master,
					"Voulez-vous vraiment vous déconnecter ?",
					"Déconnexion", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
				try {
					this.messageController.performDisconnect() ;
				} 
				catch (SendSignalException e1) { } 
				catch (UserNotConnected e1) { }
			}
		}
		else if (e.getSource() == this.quitItem) {
			if (JOptionPane.showConfirmDialog(this.master,
					"Voulez-vous vraiment quitter ?",
					"Quitter", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
				try {
					this.messageController.performDisconnect() ;
				} 
				catch (SendSignalException e1) { } 
				catch (UserNotConnected e1) { }
				System.exit(1) ;
			}
		}
		else if (e.getSource() == this.openTabItem) {
			this.openTabListener.openTab(null) ;
		}
		else if (e.getSource() == this.changeLoginItem) {
			this.dialogLogin.setVisible(true) ;
		}
		else if (e.getSource() == this.closeTabItem) {
			this.openTabListener.closeSelectedTab() ;
		}
		else if (e.getSource() == this.sendFileItem) {
			this.sendFileAction.actionPerformed(e) ;
		}
		else {
			/* Commun code for all the dialog... */
			JDialog dial = null ;
			if (e.getSource() == this.aproposItem && !this.aproposDialog.isVisible()) {
				dial = this.aproposDialog ;
			}
			else if (e.getSource() == this.networkConfigItem && !this.networkConfigDialog.isVisible()) {
				dial = this.networkConfigDialog ;
			}
			else if (e.getSource() == this.connectItem && !this.messageController.connected()) {
				dial = this.connectDialog ;
			}
			if (dial != null) {
				dial.setVisible(true) ;
			}
		}
	}
	
}
